<?php

namespace Model;

use Daiyong\Db as db;
use Daiyong\File as file;
use Daiyong\Func as func;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

class Common {
    public $config = array();
    public function __construct() {
        global $_CONFIG;
        $this->config = $_CONFIG;
    }
    /**
     * @description: 补充关系列表里面每列的father信息
     * @param {*} $list 关系数据表
     * @param {*} $key
     * @return {*}
     */
    public function typeAddFatherInfo($list, $key = []) {
        $id = $key['id'] ? $key['id'] : 'id';
        $fid = $key['fid'] ? $key['fid'] : 'fid';
        $father = $key['father'] ? $key['father'] : 'father';
        $newList = [];
        foreach ($list as $k => $v) {
            $v[$father] = [];
            $currentFid = $v[$fid];
            while ($currentFid > 0) {
                $found = false;
                //循环判断father
                foreach ($list as $v2) {
                    if ($v2[$id] == $currentFid) {
                        $v[$father][] = $v2;
                        $currentFid = $v2[$fid];
                        $found = true;
                        break;
                    }
                }
                // 如果没有找到父级，则退出循环
                if (!$found)  $currentFid = -1;
            }
            $v[$father] = array_reverse($v[$father]);
            $newList[$k] = $v;
        }
        return $newList;
    }
    /**
     * @description: 查询条件中如果有为空的(不包含数字0)则去除
     * @param {Array} $data
     * @return {*}
     */
    public function findClear($data) {
        return array_filter($data, function ($v) {
            if ($v === '0' || $v === 0) {
                return true;
            } else {
                return  $v && $v !== '%' && $v !== '%%';
            }
        });
    }
    /**
     * @description: 导出excel
     * @param {*} $title 第一行标题
     * @param {*} $callback function callback($limit){...}
     * @return {*} excel文件
     */
    public function exportExcel($title, $callback) {
        $pageCount = 10000; //分批从数据库查询每次查询数量
        $filePathNoExt = file::path('cache/excel/' . date('Ymd') . '/' . date('YmdHis') . '_' . func::random(5), true);
        $isExcel = true;
        //设置数据
        for ($i = 0; $i > -1; $i = $i + $pageCount) {
            $list = array_values($callback('limit ' . $i . ',' . $pageCount));
            if ($i === 0) {
                if (count($list) < $pageCount) {
                    $filePath = $filePathNoExt . '.xlsx';
                    //设置标题
                    $spreadsheet = new Spreadsheet();
                    $sheet = $spreadsheet->getActiveSheet();
                    $sheet->fromArray($title, NULL, 'A1');
                } else {
                    $isExcel = false;
                    $filePath = $filePathNoExt . '.csv';
                    //设置标题
                    file::put($filePath, '"' . implode('","', $title) . '"', true);
                }
            }
            if ($isExcel) {
                $sheet->fromArray($list, NULL, 'A' . (1 + $i + 1));
            } else {
                $csvData = array();
                foreach ($list as $k => $v) {
                    $csvData[] = '"' . implode('","', str_replace('"', '""', $v)) . '"';
                }
                file::put($filePath, implode(PHP_EOL, $csvData), true);
            }
            if (count($list) < $pageCount) break;
        }
        if ($isExcel) {
            $writer = new Xlsx($spreadsheet);
            $writer->save($filePath);
        }
        return $filePath;
    }
    /**
     * @description: 验证
     * @param {数据} $data
     * @param {规则} $rule
     * @param {主键} $id
     * @return {不通过返回string,通过返回true}
     */
    public function verify($data, $rule, $idKey = 'id') {
        //如果数组中有null,则将值变为空(一般是$_GET['xxx']没有的时候赋值的)
        foreach ($data as $k => $v) {
            if ($v === null) $data[$k] = '';
        }
        foreach ($rule as $k => $v) {
            if (is_string($v[0])) { //一维数组则转换成二维数组
                $v = array($v);
            }
            list($key, $must) = explode('|', $k); //拆分出key与must
            foreach ($v as $v2) { //循环每个 键值里面的条件
                if (isset($data[$key]) && $data[$key] !== '') { //有值
                    $verifyCase = $this->verifyCase($data, $key, $v2);
                    if ($verifyCase !== true) {
                        return $verifyCase;
                    }
                } elseif (!$data[$key] && $must) { //无值且必须
                    if ($data[$idKey]) { //修改时
                        if (isset($data[$key])) { //不能改为空
                            return $key . '不能为空';
                        }
                    } else { //新增时
                        return $key . '不能为空';
                    }
                }
            }
        }
        return true;
    }
    private function verifyCase($data, $key, $rule) {
        switch ($rule[0]) {
            case 'callback': //执行回调方法
                $return = $rule[1]($data[$key]);
                if ($return) return $return;
                break;
            case 'idInTable': //id是否在一个表或者一个数组里面
                if (
                    !db::find($rule[2] . '|id', array('id' => $data[$key])) &&
                    !($rule[3] && in_array($data[$key], $rule[3]))
                ) {
                    return $rule[1];
                }
                break;
            case 'only': //唯一判断
                $where = array($key => $data[$key]);
                if ($data['id']) { //如果是修改则过滤自己的重复判断
                    $where['id|!='] = $data['id'];
                }
                if (db::find($rule[2] . '|id', $where)) {
                    return $rule[1];
                }
                break;
            case 'reg':
                if (!preg_match($rule[2], $data[$key])) {
                    return $rule[1];
                }
                break;
            case 'date':
                if (!isDate($data[$key])) {
                    return $rule[1];
                }
                break;
            case 'time':
                if (!isTime($data[$key])) {
                    return $rule[1];
                }
                break;
            case 'phone':
                if (!isPhone($data[$key])) {
                    return $rule[1];
                }
                break;
            case 'mail':
                if (!isMail($data[$key])) {
                    return $rule[1];
                }
                break;
            case 'int':
                if (!is_numeric($data[$key])) {
                    return $rule[1];
                }
                if (isset($rule[2]) && $data[$key] < $rule[2]) {
                    return $rule[1];
                };
                if (isset($rule[3]) &&  $data[$key] > $rule[3]) {
                    return $rule[1];
                };
                break;
            case 'string':
                $len = mb_strlen($data[$key]);
                if (isset($rule[2]) && $len < $rule[2]) {
                    return $rule[1];
                };
                if (isset($rule[3]) && $len > $rule[3]) {
                    return $rule[1];
                };
                break;
            case 'array':
                if (!is_array($data[$key])) {
                    return $rule[1];
                }
                break;
            case 'stringName': //一般用作用户昵称使用(3个\w记为1个字符,如果\w太短则1个\w作为1个字符)
                $len = mb_strlen($data[$key]);
                //将(每3个英文与数字)计算成一个字符
                preg_match_all('/[\w]+/', $data[$key], $matches);
                $res = implode('', $matches[0]);
                $len = $len - (int)(strlen($res) - strlen($res) / 3);
                if ($len < $rule[2]) {
                    //英文最小长度转换成实际长度再计算
                    if (preg_match('/^[\w]+$/', $data[$key])) {
                        if (strlen($data[$key]) < $rule[2]) {
                            return $rule[1];
                        }
                    } else {
                        return $rule[1];
                    }
                }
                if ($len > $rule[3]) {
                    return $rule[1];
                }
                break;
        }
        return true;
    }

    /**
     * @description: 由于model中所有信息都使用字符串返回,这里主要用于验证edit不通过的返回的特定格式
     * @param {*} $message
     * @return {*}
     */
    public function error($message = '失败') {
        return array(
            'status' => 0,
            'message' => $message
        );
    }
    /**
     * @description: 将表中的varchar与char类型的支付组合起来并添加到search字段
     * @param {*} $table 表名称
     * @param {*} $id id
     * @param {*} $deleteFiled 需要排除的字段
     * @return {*}
     */
    public function createSearchField($table, $id, $searchKey = 'search') {
        $info = db::find($table, ['id' => $id]);
        $field = [];
        //数据表注释,对开头以s,开头的进行处理
        $tableComment = db::findAll('information_schema.COLUMNS|COLUMN_NAME,COLUMN_COMMENT', [
            'TABLE_SCHEMA' => db::find('SELECT DATABASE()'),
            'TABLE_NAME' => $table
        ], 'COLUMN_NAME');
        if (!isset($tableComment[$searchKey])) return false;
        //关系映射变为字符串
        $config = new \Model\Config();
        $relation = $config->relation();
        $status = $config->status();
        //字段重组
        $tableInfo = db::findAll('DESC ' . $table);
        foreach ($tableInfo as $v) {
            $relationInfo = $relation[$table][$v['Field']];
            $statusInfo = $status[$table][$v['Field']];
            //table关系映射
            if ($relationInfo) { //id对应
                $field[$v['Field']] = db::find($relationInfo['table'] . '|' . $relationInfo['value'], [
                    $relationInfo['id'] ? $relationInfo['id'] : 'id' => $info[$v['Field']]
                ]);
            } else if ($statusInfo) { //status对应关系
                $field[$v['Field']] = $statusInfo[$info[$v['Field']]];
            } else if (strpos($tableComment[$v['Field']], 's,') === 0) { //注释开头携带s,
                $field[$v['Field']] = $info[$v['Field']];
            }
        }
        $field = array_filter($field, function ($value) {
            return trim($value) !== '';
        });
        //修改数据表$searchKey字段
        return db::update($table, [$searchKey => implode(',', $field)], ['id' => $id]);
    }
}
